package utils

import (
	"os"
	"path"
	"runtime"
	"time"

	"github.com/lestrrat/go-file-rotatelogs"
	"github.com/rifflock/lfshook"
	logrus "github.com/sirupsen/logrus"
)

type Logs struct {
	IsPrintFileUrl bool           //日志中是否打印
	IsWriteFile    bool           //是否将日志写入文件
	LogFiLeUrl     string         //日志路径
	LogFileName    string         //日志名字
	LogLevel       string         //日志等级. Debug,Info,Warn,Error
	obj            *logrus.Logger //日志对象
}

var Log *Logs

func (l *Logs) Init() {
	/*  设置日志 */
	// 为当前logrus实例设置消息的输出，同样地，
	// 可以设置logrus实例的输出到任意io.writer
	l.obj = logrus.New()

	l.obj.Out = os.Stdout

	//debug日志中是否打印路径
	// if l.IsPrintFileUrl =nil{
	// 	l.IsPrintFileUrl=false
	// }
	// if l.IsWriteFile=nil{
	// 	l.IsWriteFile=false
	// }

	// 为当前logrus实例设置消息输出格式为json格式。
	// 同样地，也可以单独为某个logrus实例设置日志级别和hook，这里不详细叙述。
	//log.Formatter = &logrus.JSONFormatter{}
	//设置日志打印级别
	switch l.LogLevel {
	case "Debug":
		l.obj.SetLevel(logrus.DebugLevel)
	case "Info":
		l.obj.SetLevel(logrus.InfoLevel)
	case "Warn":
		l.obj.SetLevel(logrus.WarnLevel)
	case "Error":
		l.obj.SetLevel(logrus.ErrorLevel)
	default:
		l.obj.SetLevel(logrus.InfoLevel)
	}
	//输出到文件
	if l.IsWriteFile {
		if l.LogFiLeUrl == "" {
			l.LogFiLeUrl = "./log/"
		}
		if l.LogFileName == "" {
			l.LogFileName = "LogInfo.log"
		}
		PathExists(l.LogFiLeUrl, true)
		l.configLocalFilesystemLogger(l.LogFiLeUrl, l.LogFileName, 10, time.Hour)
	}
	Log = l
}
func (l *Logs) Debug(args ...interface{}) {
	l.showLog(logrus.DebugLevel, args...)
}
func (l *Logs) Info(args ...interface{}) {
	l.showLog(logrus.InfoLevel, args...)
}
func (l *Logs) Warn(args ...interface{}) {
	l.showLog(logrus.WarnLevel, args...)
}
func (l *Logs) Error(args ...interface{}) {
	l.showLog(logrus.ErrorLevel, args...)
}
func (l *Logs) Fatal(args ...interface{}) {
	n, f, lin := printMyName(2)
	if l.IsPrintFileUrl {
		l.obj.WithFields(
			logrus.Fields{
				"sour": n,
				"file": f,
				"line": lin,
				//"size": 10,
			},
		).Fatal(args...)
	} else {
		l.obj.WithFields(
			logrus.Fields{
				"sour": n,
				"line": lin,
			},
		).Fatal(args...)
	}
}

func (l *Logs) showLog(level logrus.Level, args ...interface{}) {
	n, f, lin := printMyName(3)
	if l.IsPrintFileUrl {
		l.obj.WithFields(
			logrus.Fields{
				"sour": n,
				"file": f,
				"line": lin,
				//"size": 10,
			},
		).Log(level, args...)
	} else {
		l.obj.WithFields(
			logrus.Fields{
				"sour": n,
				"line": lin,
			},
		).Log(level, args...)
	}
}

// config logrus log to local filesystem, with file rotation
func (l *Logs) configLocalFilesystemLogger(logPath string, logFileName string, maxRemainCnt int, rotationTime time.Duration) {
	baseLogPaht := path.Join(logPath, logFileName)
	writer, err := rotatelogs.New(
		baseLogPaht+".%Y%m%d%H%M",
		// WithLinkName为最新的日志建立软连接，以方便随着找到当前日志文件
		rotatelogs.WithLinkName(baseLogPaht), // 生成软链，指向最新日志文件

		// WithRotationTime设置日志分割的时间，设置time.Hour为一小时分割一次

		rotatelogs.WithRotationTime(rotationTime), // 日志切割时间间隔

		// WithMaxAge和WithRotationCount二者只能设置一个，
		// WithMaxAge设置文件清理前的最长保存时间，
		// WithRotationCount设置文件清理前最多保存的个数。
		//rotatelogs.WithMaxAge(time.Hour*24), // 文件最大保存时间

		rotatelogs.WithRotationCount(maxRemainCnt), //最多保存个数
	)
	if err != nil {
		l.Error("config local file system logger error. ", err)
	}
	lfHook := lfshook.NewHook(lfshook.WriterMap{
		logrus.DebugLevel: writer, // 为不同级别设置不同的输出目的
		logrus.InfoLevel:  writer,
		logrus.WarnLevel:  writer,
		logrus.ErrorLevel: writer,
		logrus.FatalLevel: writer,
		logrus.PanicLevel: writer,
	}, &logrus.TextFormatter{DisableColors: true})
	l.obj.AddHook(lfHook)
}

func printMyName(fNum int) (string, string, int) {
	pc, fileName, lineNum, _ := runtime.Caller(fNum)
	return runtime.FuncForPC(pc).Name(), fileName, lineNum
}

/*
printMyName 代码来源:https://colobu.com/2018/11/03/get-function-name-in-go/
ConfigLocalFilesystemLogger  代码来源https://www.jianshu.com/p/9e12fad671aa
*/
